/* NOTICE
 
    Jim - the Java Image Manager, copyright (c) 2005 - 2007 Grant Gardner 
 
    Jim is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Jim is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  
    In addition, as a special exception, you are permitted to link this code
    with the 3rd party libraries required to compile this file and to
    distribute a linked combination including them. You must obey the
    GNU General Public License in all respects for all of the code except for
    those 3rd party libraries that are licenced under terms incompatible with the
    GNU General Public License.  
 
 
 NOTICE */

package au.com.lastweekend.desktop.freedesktop;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.log4j.Logger;

import au.com.lastweekend.jim.util.IniReader;
import au.com.lastweekend.jim.util.IniSection;

/**
 * See http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
 * 
 * @author grant@lastweekend.com.au
 * @version $Id: codetemplates.xml,v 1.2 2005/01/22 06:53:11 ggardner Exp $
 */
public class IconTheme {

    private static final String ICONS = "icons";
    private static final String PIXMAPS = "pixmaps";

    private static final Logger LOG = Logger.getLogger(IconTheme.class);
    public static final IconTheme NULL_THEME = new IconTheme();

    private String theme;
    private Map<String, IniSection> sections;
    private List<String> subDirectories;
    private List<IconTheme> parents;
    private Collection<File> baseDirs;

    private IconTheme() {

        baseDirs = Collections.emptyList();
        this.theme = "No Theme";
    }

    public IconTheme(Collection<File> baseDirs, String theme) throws IOException {

        this.baseDirs = baseDirs;
        this.theme = theme;

        for (File baseDir : baseDirs) {
            File themeIndex = new File(baseDir, ICONS + "/" + theme + "/index.theme");
            if (themeIndex.exists()) {
                IniReader reader = new IniReader(themeIndex);
                sections = reader.readAllSections();
                break;
            }

        }

    }

    public String findIcon(String icon, int preferredSize) {

        if (sections != null) {
            List<String> subdirs = getSubDirectories();
            // Didn't find an exact match...
            int closestSize = Integer.MAX_VALUE;
            File closestFile = null;
            for (String subdir : subdirs) {
                int subDirSize = getDirectorySize(subdir);
                if (subDirSize > 0) {
                    int dist = Math.abs(subDirSize - preferredSize);
                    if (dist < closestSize) {
                        for (File baseDir : baseDirs) {
                            File iconFile = getIconFile(baseDir, subdir, icon);
                            if (iconFile.exists()) {
                                closestFile = iconFile;
                                if (dist == 0) {
                                    return closestFile.getAbsolutePath();
                                }
                            }
                        }

                    }
                }
            }
            if (closestFile != null) {
                return closestFile.getAbsolutePath();
            }

            List<IconTheme> parents = getParents();
            for (IconTheme parent : parents) {
                String result = parent.findIcon(icon, preferredSize);
                if (result != null) {
                    return result;
                }
            }
        }

        for (File baseDir : baseDirs) {
            File iconFile = new File(baseDir, PIXMAPS + "/" + icon + ".png");
            if (iconFile.exists()) {
                return iconFile.getAbsolutePath();
            }
        }
        return null;

    }

    private List<IconTheme> getParents() {

        if (parents == null) {
            IniSection iniSection = sections.get("Icon Theme");
            if (iniSection != null) {
                String inheritedThemes = iniSection.getKey("Inherits");
                if (inheritedThemes != null) {
                    StringTokenizer tokenizer = new StringTokenizer(inheritedThemes, ",");
                    parents = new ArrayList<IconTheme>(tokenizer.countTokens());
                    while (tokenizer.hasMoreTokens()) {
                        String parentTheme = tokenizer.nextToken();
                        try {
                            IconTheme iconTheme;
                            iconTheme = new IconTheme(baseDirs, parentTheme);
                            parents.add(iconTheme);
                        } catch (IOException e) {
                            LOG.warn("Unable to open inherited theme " + parentTheme, e);
                        }
                    }

                }
            }

            if (parents == null || parents.isEmpty()) {
                if (theme.equals("hicolor")) {
                    parents = Collections.emptyList();
                } else {
                    IconTheme hicolorTheme;
                    try {
                        hicolorTheme = new IconTheme(baseDirs, "hicolor");
                        parents = Collections.singletonList(hicolorTheme);
                    } catch (IOException e) {
                        LOG.warn("Unable to load default theme - hicolor", e);
                        parents = Collections.emptyList();
                    }
                }
            }
        }

        return parents;
    }

    private File getIconFile(File baseDir, String subdir, String icon) {

        return new File(baseDir, ICONS + "/" + theme + "/" + subdir + "/" + icon + ".png");

    }

    private List<String> getSubDirectories() {

        if (subDirectories == null) {
            IniSection iniSection = sections.get("Icon Theme");
            if (iniSection != null) {
                String directories = iniSection.getKey("Directories");
                if (directories != null) {
                    StringTokenizer tokenizer = new StringTokenizer(directories, ",");
                    subDirectories = new ArrayList<String>();
                    while (tokenizer.hasMoreTokens()) {
                        subDirectories.add(tokenizer.nextToken());
                    }
                }
            }

            if (subDirectories == null) {
                subDirectories = Collections.emptyList();
            }
        }

        return subDirectories;

    }

    private int getDirectorySize(String subdir) {

        int subDirSize = -1;
        IniSection iniSection = sections.get(subdir);
        if (iniSection != null) {
            String sizeKey = iniSection.getKey("Size");
            if (sizeKey != null) {
                try {
                    subDirSize = Integer.parseInt(sizeKey);
                } catch (NumberFormatException e) {
                    LOG.debug("Bad Size for " + subdir, e);
                }
            }
        }
        return subDirSize;
    }

    public String getThemeName() {

        return theme;
    }

}
